package xyz.haijin.mybatisplus.bean;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import xyz.haijin.mybatisplus.annotation.MpQuery;
import xyz.haijin.mybatisplus.annotation.OrderBy;
import xyz.haijin.mybatisplus.model.PageBean;
import xyz.haijin.mybatisplus.model.PageInfo;
import xyz.haijin.mybatisplus.constant.QueryConstant;
import xyz.haijin.mybatisplus.util.BeanUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liuhaijin
 * @date 2022/4/2
 * D 请求实体类 T 数据库实体类 R 返回的实体类
 */
public class MybatisPusBean<D,T,R> {

    private IService<T> iService;

    private PageInfo pageInfo;

    private D d;

    private Class<T> tClass;

    private Class<R> rClass;

    private IPage<T> tPage;

    private IPage<R> rPage;

    List<OrderByBean> orderByBeans = new ArrayList<OrderByBean>();


    // 属性字段
    private Map<String, ColumnBean> columnMap = new HashMap<>();



    public MybatisPusBean(PageInfo pageInfo, IService<T> iService, D d, Class<T> tClass, Class<R> rClass) {
        this.pageInfo = pageInfo;
        this.iService = iService;
        this.d = d;
        this.tClass = tClass;
        this.rClass = rClass;
        this.tPage = new Page<>(pageInfo.getCurrent(),pageInfo.getPageSize());
        this.rPage = new Page<>(pageInfo.getCurrent(),pageInfo.getPageSize());
    }

    public MybatisPusBean( D d, Class<T> tClass, Class<R> rClass) {
        this.d = d;
        this.tClass = tClass;
        this.rClass = rClass;
    }

    public MybatisPusBean(IPage<R> rPage,D d, Class<T> tClass, Class<R> rClass) {
        this.d = d;
        this.tClass = tClass;
        this.rClass = rClass;
        this.rPage = rPage;
    }

    /**
     * 实体对象查询
     * @return
     */
    public LambdaQueryWrapper<T> getLambdaQueryWrapper() {
        return getQueryWrapper().lambda();
    }

    /**
     * 分页查询
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public IPage<T> getPage()  {
        if (iService == null || tPage == null) {
            return null;
        }
        return iService.page(tPage,getLambdaQueryWrapper());
    }


    /**
     * 获取PageBean的分页数据
     * @return
     */
    public PageBean<T> getPageBean() {
        IPage<T> page = getPage();
        return new PageBean<T>(page.getCurrent(),page.getSize(),page.getPages(),page.getTotal(),page.getRecords());
    }


    /**
     * 获取返回实体类的数据
     * @return
     */
    public IPage<R> getPageR() {
        IPage<T> page = getPage();
        List<T> tList = page.getRecords();
        if (rPage == null) {
            return null;
        }
        List<R> rList = BeanUtils.copyProperties(tList, rClass);
        rPage.setRecords(rList);
        rPage.setCurrent(page.getCurrent());
        rPage.setSize(page.getSize());
        rPage.setPages(page.getPages());
        rPage.setTotal(page.getTotal());
        return rPage;
    }


    /**
     * 获取返回实体类PageBeanR的分页数据
     * @return
     */
    public PageBean<R> getPageBeanR() {
        IPage<R> page = getPageR();
        return new PageBean<>(page.getCurrent(), page.getSize(), page.getPages(), page.getTotal(), page.getRecords());
    }

    /**
     * 实体对象查询
     * @return
     */
    public QueryWrapper<T> getQueryWrapper() {
        T t = null;
        try {
            t = checkAnnotation(d);
        } catch (IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
        QueryWrapper<T> queryWrapper = Wrappers.query(t);
        if (orderByBeans.size() != 0) {
            List<String> asc = new ArrayList<String>();
            List<String> desc = new ArrayList<String>();
            List<OrderByBean> collect = orderByBeans.stream().sorted((Comparator.comparing(OrderByBean::getSort))).collect(Collectors.toList());
            for (OrderByBean orderByBean : collect) {
                if (QueryConstant.ASC.equals(orderByBean.getOrderByValue())) {
                    asc.add(orderByBean.getColumn());
                } else if (QueryConstant.DESC.equals(orderByBean.getOrderByValue())) {
                    desc.add(orderByBean.getColumn());
                }
            }
            if (asc.size() != 0) {
                queryWrapper.orderByAsc(String.valueOf(asc.toArray(new String[0])));
            }
            if (desc.size() != 0) {
                queryWrapper.orderByDesc(String.valueOf(desc.toArray(new String[0])));
            }
        }
        return buildQueryWrapper(queryWrapper);
    }

    private QueryWrapper<T>  buildQueryWrapper(QueryWrapper<T> queryWrapper) {
        if (columnMap.size() != 0) {
            for (Map.Entry<String, ColumnBean> stringColumnBeanEntry : columnMap.entrySet()) {
                ColumnBean columnBean = stringColumnBeanEntry.getValue();
                // TODO 构建查询条件
                switch (columnBean.getQueryCondition()) {
                    case QueryConstant.LIKE_RIGHT: // 右模糊查询
                        queryWrapper.likeRight(columnBean.getQueryValue(),columnBean.getColumnValue());
                        break;
                    case QueryConstant.GE: //大于等于
                        queryWrapper.ge(columnBean.getQueryValue(),columnBean.getColumnValue());
                        break;
                    case  QueryConstant.LE: //小于等于
                        queryWrapper.le(columnBean.getQueryValue(),columnBean.getColumnValue());
                        break;
                    default:
                        break;
                }
            }
        }
        return queryWrapper;
    }


    /**
     * 校验注解
     * @param d 传入的数据实体对象
     */
    private T checkAnnotation(D d) throws IllegalAccessException, InstantiationException {
        T t = tClass.newInstance();
        Class<?> dClass = d.getClass();
        // 向上循环 遍历父类
        for (; dClass != Object.class; dClass = dClass.getSuperclass()) {
            for (Field field : dClass.getDeclaredFields()) {
                if (field.getAnnotation(MpQuery.class) != null) {
                    String value = field.getAnnotation(MpQuery.class).value();
                    if ("".equals(value)) {
                        setFieldValue(field,t);
                        continue;
                    }
                    field.setAccessible(true);
                    Object object = field.get(d);
                    if (object != null) {
                        String condition = field.getAnnotation(MpQuery.class).condition();
                        ColumnBean columnBean = new ColumnBean();
                        String name = field.getName();
                        columnBean.setColumnName(name);
                        columnBean.setColumnValue(object);
                        columnBean.setQueryCondition(condition);
                        columnBean.setQueryValue(value);
                        columnMap.put(name,columnBean);
                    }
                } else {
                    setFieldValue(field,t);
                }
                if (field.getAnnotation(OrderBy.class) != null) {
                    String sortValue = field.getAnnotation(OrderBy.class).sortValue();
                    String column = field.getAnnotation(OrderBy.class).value();
                    int sort = field.getAnnotation(OrderBy.class).sort();
                    OrderByBean orderByBean = new OrderByBean();
                    orderByBean.setColumn(column);
                    orderByBean.setOrderByValue(sortValue);
                    orderByBean.setSort(sort);
                    orderByBeans.add(orderByBean);
                }
            }
        }
        return t;
    }

    /**
     * 通过反射设置字段值
     * @param field
     * @return
     */
    private void setFieldValue(Field field,T t) throws IllegalAccessException {
        for (Field tClassField : tClass.getDeclaredFields()) {
            // 判断反射的Field是不是用final修饰
            if (Modifier.isFinal(field.getModifiers())) {
                return;
            }
            if (tClassField.getName().equals(field.getName())) {
                field.setAccessible(true);
                Object object = field.get(d);
                tClassField.setAccessible(true);
                tClassField.set(t,object);
            }
        }
    }

}

